import emptyImg from '@/assets/svgs/empty-img.svg'
/* eslint-disable */
/**
 * MoveBall 类，用于实现元素在两个 DOM 节点之间的动画移动。
 *
 * 参考：{@link https://juejin.cn/post/7338973258895753279}
 */
class MoveBall {
  /**
   * 创建一个新的 MoveBall 实例。
   * @param {Object} options - 构造函数选项对象。
   * @param {Element} options.startDom - 开始位置的 DOM 元素。
   * @param {Element} options.endDom - 结束位置的 DOM 元素。
   * @param {number} [options.duration=800] - 动画持续时间（毫秒），默认为 800。
   * @param {string} [options.ballImg=emptyImg] - 移动球的图片，默认为 `emptyImg`。
   * @param {string} [options.ballBgColor='#fff'] - 移动球的背景颜色，默认为 `#fff`。
   * @param {string} [options.ballBorderRadius='50%'] - 移动球的边框圆角，默认为 `'50%'`。
   * @param {boolean} [options.isPopAnimateFirst=true] - 是否先执行弹跳动画，默认为 `true`。
   */
  constructor({
    startDom,
    endDom,
    duration = 800,
    ballImg = emptyImg,
    ballBgColor = '#fff',
    ballBorderRadius = '50%',
    isPopAnimateFirst = true
  }) {
    this.startXy = MoveBall.getCenterCoordinates(startDom)
    this.endXy = MoveBall.getCenterCoordinates(endDom)
    this.verticalDom = MoveBall.createVerticalDom(startDom)
    this.horizontalDom = MoveBall.createHorizontalDom({ ballBgColor, ballImg })
    // # verticalDom 包含 horizontalDom
    this.verticalDom.appendChild(this.horizontalDom)
    this.ballImg = ballImg
    this.ballBorderRadius = ballBorderRadius
    this.isPopAnimateFirst = isPopAnimateFirst

    this.duration = duration
    if (isPopAnimateFirst) {
      this.totalDuration = duration + MoveBall.stopDelay
    } else {
      this.totalDuration = duration
    }
  }
  static ballW = 30
  static ballH = 30
  static stopDelay = 500
  static WIN = window || globalThis
  static getCenterCoordinates(domElement) {
    if (!domElement) {
      const viewportHeight =
        MoveBall.WIN.innerHeight ||
        MoveBall.WIN.document.documentElement.clientHeight
      const viewportWidth =
        MoveBall.WIN.innerWidth ||
        MoveBall.WIN.document.documentElement.clientWidth
      return {
        x: viewportWidth / 2,
        y: viewportHeight / 2
      }
    }
    const rect = domElement.getBoundingClientRect()
    const centerX = rect.left + rect.width / 2
    const centerY = rect.top + rect.height / 2
    return { x: centerX, y: centerY }
  }
  // 这个垂直用来设置轨迹的(我的理解)
  static createVerticalDom(startDom) {
    const startXy = MoveBall.getCenterCoordinates(startDom)
    const verticalDom = document.createElement('div')
    verticalDom.style.position = 'fixed'
    verticalDom.style.top = `${startXy.y - MoveBall.ballH / 2}px`
    verticalDom.style.left = `${startXy.x - MoveBall.ballW / 2}px`
    verticalDom.style.zIndex = '999'
    verticalDom.style.backgroundColor = 'transparent'
    return verticalDom
  }
  /**
   * 水平方向才能设置肉眼看到的样式(不然样式奇怪)
   */
  static createHorizontalDom({ ballBgColor, ballImg }) {
    const horizontalDom = document.createElement('div')
    horizontalDom.style.width = `${MoveBall.ballW}px`
    horizontalDom.style.height = `${MoveBall.ballH}px`
    horizontalDom.style.borderRadius = this.ballBorderRadius
    horizontalDom.style.border = '1px solid #dddddd'
    horizontalDom.style.background = `url('${ballImg}') center / cover no-repeat, ${ballBgColor}`
    return horizontalDom
  }
  getOffsetXy() {
    return {
      x: this.endXy.x - this.startXy.x,
      y: this.endXy.y - this.startXy.y
    }
  }
  freeThrow(cb) {
    const _this = this
    document.body.appendChild(this.verticalDom)
    let verticalEasing =
      this.startXy.y < this.endXy.y
        ? 'cubic-bezier(.44,-1.43,1,1)'
        : 'cubic-bezier(0,0,.76,1.45)'
    //! cubic-bezier(0,0,.76,1.92) 在 x = 0.76 时， y = 1.92，表示动画在进程为 0.76 时速度为 1.92，达到最大速度。

    this.isPopAnimateFirst &&
      this.verticalDom.animate(
        [
          {
            opacity: '0.7',
            transform: `scale(4)`
          },
          {
            opacity: '0.9',
            transform: `scale(1)`
          },
          {
            opacity: '0.8',
            transform: `scale(1.6)`
          },
          {
            opacity: '1',
            transform: `scale(1)`
          }
        ],
        {
          easing: `ease`,
          duration: MoveBall.stopDelay,
          iterations: 1
        }
      )

    const delay = (this.isPopAnimateFirst && MoveBall.stopDelay) || 0
    let verticalAnimate = this.verticalDom.animate(
      [
        {
          transform: `translate3d(0, ${this.getOffsetXy().y}px, 0)`
        }
      ],
      {
        delay,
        easing: verticalEasing,
        duration: this.duration,
        iterations: 1
      }
    )
    this.horizontalDom.animate(
      [
        { transform: `translate3d(0px, 0, 0) scale(1)` },
        { transform: `translate3d(${this.getOffsetXy().x}px, 0, 0) scale(.5)` }
      ],
      {
        delay,
        easing: 'linear',
        duration: this.duration,
        iterations: 1
      }
    )
    // 动画完成
    verticalAnimate.onfinish = () => {
      typeof cb === 'function' && cb(_this)
      this.verticalDom.remove()
    }
  }
}

/**
 * 动画移动函数，使元素从一个 DOM 节点移动到另一个 DOM 节点。
 * @function moveBallWithAnimation
 * @param {Object} options - 动画参数对象。
 * @param {Element} options.startDom - 开始位置的 DOM 元s素。
 * @param {Element} options.endDom - 结束位置的 DOM 元素。
 * @param {string} [options.ballImg=emptyImg] - 移动球的图片，默认为 `emptyImg`。
 * @param {string} [options.ballBgColor='#fff'] - 移动球的背景颜色，默认为 `#fff`。
 * @param {number} [options.ballSize=40] - 移动球的大小，默认为 `40`。
 * @param {string} [options.ballBorderRadius='50%'] - 移动球的边框圆角，默认为 `'50%'`。
 * @param {number} [options.duration=800] - 动画持续时间，默认为 `800` 毫秒。
 * @param {boolean} [options.isPopAnimateFirst=true] - 是否先执行弹跳动画，默认为 `true`。
 * @param {Function} [options.onFinish=()=>{}] - 动画完成后的回调函数，默认为空函数。
 * @returns {MoveBall} 返回创建的 `MoveBall` 实例。
 */
function moveBallWithAnimation({
  startDom,
  endDom,
  ballImg = emptyImg,
  ballBgColor = '#fff',
  ballSize = 40,
  ballBorderRadius = '50%',
  duration = 800,
  isPopAnimateFirst = true,
  onFinish = () => {}
}) {
  const WIN = window || globalThis
  if (!(endDom instanceof WIN.Element)) {
    return console.warn('endDom is not Element')
  }
  MoveBall.ballH = ballSize
  MoveBall.ballW = ballSize
  const moveBall = new MoveBall({
    startDom,
    endDom,
    duration,
    ballImg,
    ballBgColor,
    ballBorderRadius,
    isPopAnimateFirst
  })
  moveBall.freeThrow(onFinish)
  return moveBall
}

/* eslint-enable */

export { MoveBall, moveBallWithAnimation }
